#pragma once

#include <stdbool.h>

//虚拟机指令集
enum InstrType {
  InsJtrue,  //为真则跳转  (InsJtrue, arg1, , dest)
  InsJfalse, //为假则跳转  (InsJfalse,arg1, , dest)
  InsJmp,    //无条件跳转  (InsJmp,  ,   , dest)
  InsMov,    //数据复制      (InsMov, arg1,    ,dest)
  InsInit,   //初始化某单元  (InsInit,arg1,num,     )
  InsAdd,    //加法      (InsAdd, arg1,arg2,dest)
  InsSub,    //减法      (InsSub, arg1,arg2,dest)
  InsMul,    //乘法      (InsMul, arg1,arg2,dest)
  InsDiv,    //除法      (InsDiv, arg1,arg2,dest)
  InsMod,    //取余
  InsNop,    //空操作    (InsNop,  ,  ,   )
  InsJlt,    //判断是否<    (InsLt,arg1,arg2,result)
  InsJle,    //判断是否<=  (InsLe,arg1,arg2,result)
  InsJgt,    //判断是否>    (InsGt,arg1,arg2,result)
  InsJge,    //判断是否>=
  InsJeq,    //判断是否==
  InsJne,    //判断是否!=
  InsOr,     //逻辑或运算
  InsAnd,    //逻辑与运算
  InsNot,    //逻辑非运算
  InsIn,     //读入一个整数到单元dest (InsIn,dest , ,);
  InsOut,    //输出一个整数  (InsOut,num, ,);
  InsUminus, //负数      (InsUminus,oprn, ,dest)
  InsCall,   //过程调用    (InsCall,des, , ,);
  InsRet,    //过程返回    (InsRet,expr, , );
  InsSetBx,  //设置bx指针，指向活动记录首地址(InsSetBx,addr, , )
  InsAddBx,  // bx指针增加      (InsSetBx,addr);
};

typedef struct {
  int optr;
  int arg1;
  int arg2;
  int result;
} Instruction;

typedef struct {
  int pc; // program counter
  int bx;
  int cs_index;
  int global_mem_size;

  int ds[65536];         // data segment
  Instruction cs[65536]; // code segment
} VirtualMachine;

const char *optr_to_str(int enum_value);
int str_to_optr(const char *name);

VirtualMachine* vm_create();
void vm_destroy(VirtualMachine* vm);
void vm_run(VirtualMachine* this);
bool vm_load_asm(VirtualMachine* this, const char *filename);
